﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Krile.Kernel;
using Krile.Kernel.Plugin;
using Krile.Kernel.Plugin.Operations.AgentElements;

namespace Highkick.HOperation
{
    public class HStatusControl : IStatusControl
    {
        API.HHAPI api;
        HOperation parent;
        public HStatusControl(HOperation parent)
        {
            this.parent = parent;
            api = new Highkick.API.HHAPI(new DefaultAuth());
            SidUidContainer = new List<KeyValuePair<string, ulong>>();
            recv = new ReceiveController();
        }

        ReceiveController recv;
        static object suLocker = new object();
        List<KeyValuePair<string, ulong>> SidUidContainer;

        public void BeginReceive()
        {
            Action be = new Action(BeginExecute);
            be.BeginInvoke((iar) => ((Action)iar.AsyncState).EndInvoke(iar), be);
        }

        private void BeginExecute()
        {
            ReceiveStatus();
            recv.OnReceive += new Action(ReceiveStatus);
            recv.Begin();
        }

        public ulong GetUid(string sid)
        {
            lock (suLocker)
            {
                foreach (var kv in SidUidContainer)
                {
                    if (kv.Key == sid)
                        return kv.Value;
                }
            }
            return 0;
        }

        public string GetSid(ulong uid)
        {
            lock (suLocker)
            {
                foreach (var kv in SidUidContainer)
                {
                    if (kv.Value == uid)
                        return kv.Key;
                }
            }
            return null;
        }

        public bool RegistSidUid(string sid, ulong uid)
        {
            lock (suLocker)
            {
                foreach (var kv in SidUidContainer)
                {
                    if (kv.Key == sid || kv.Value == uid)
                        return false;
                }
                SidUidContainer.Add(new KeyValuePair<string, ulong>(sid, uid));
            }
            return true;
        }

        public bool RecvGlobalTimeline { get; set; }

        public void ReceiveStatuses()
        {
            ReceiveStatus();
        }

        public bool Updatable
        {
            get
            {
                return Core.Config.Account != null;
            }
        }

        public OperationResult<object> Update(string text, ulong replyto, object affixObject)
        {
            string replyTo = GetSid(replyto);
            try
            {
                if (affixObject != null && !String.IsNullOrEmpty(affixObject as string))
                {
                    api.Update(text, null, replyTo, affixObject as string);
                }
                else
                {
                    api.Update(text, null, replyTo);
                }
            }
            catch (Exception e)
            {
                return new OperationResult<object>()
                {
                    Succeeded = false,
                    Exception = e,
                    ErrorOperation = OperationResult<object>.ErrorOperations.Worn,
                    Message = e.Message,
                    OperationUri = new Uri("http://h.hatena.ne.jp/api/statuses/update.xml")
                };
            }
            return new OperationResult<object>()
            {
                Succeeded = true,
                OperationUri = new Uri("http://h.hatena.ne.jp/api/statuses/update.xml")
            };
        }

        public bool AutoCreateReplyOperationTriggers
        {
            get { return true; }
        }

        #region not implements
        public bool AutoCreateFavOperationTriggers
        {
            get { return false; }
        }

        public bool AutoCreateDeleteOperationTriggers
        {
            get { return false; }
        }

        public bool Destroiable
        {
            get { return false; }
        }

        public OperationResult<object> Destroy(ulong uid)
        {
            throw new NotImplementedException();
        }

        #endregion

        public OperationResult<object> SetFavorite(ulong uid, bool create)
        {
            if (!create || GetSid(uid) == null)
                return new OperationResult<object>() { Succeeded = false };
            Bridge.MainForm.SetStatusText("スターを付けています...");
            try
            {
                api.AddStar(GetSid(uid));
                Bridge.MainForm.SetStatusText("スターを付けました。", 3);
                return new OperationResult<object>() { Succeeded = true };
            }
            catch (Exception e)
            {
                Bridge.MainForm.SetStatusText("スターに失敗しました:" + e.Message, 3);
                return new OperationResult<object>() { Succeeded = false, Exception = e };
            }
        }

        public ulong GetUidFromServiceStatusId(string id)
        {
            return GetUid(id);
        }

        public bool ServiceStatusIdExists(string id)
        {
            return GetUid(id) != 0;
        }

        public void ReceiveStatus()
        {
            try
            {
                var recv = api.FriendTimeline();
                var sel = from s in recv
                          where RegistSidUid(s.Id, s.UID)
                          select s;
                Bridge.StatusManager.RegistStatus(sel.ToArray().Cast<Krile.Kernel.Data.Status>());
            }
            catch (Exception fe)
            {
                Bridge.DebugReporter.AddReport(fe);
            }
            if (RecvGlobalTimeline)
            {
                try
                {
                    var recv = api.PublicTimeline();
                    var sel = from s in recv
                              where RegistSidUid(s.Id, s.UID)
                              select s;
                    Bridge.StatusManager.RegistStatus(sel.ToArray().Cast<Krile.Kernel.Data.Status>());
                }
                catch (Exception fe)
                {
                    Bridge.DebugReporter.AddReport(fe);
                }
            }

        }
    }
}
